#ifndef ATL_H
#define ATL_H

/*******************************************************************************
 *
 * Voici la librairie des template du projet ADD, ou ADD Template Library
 *
 ******************************************************************************/

#include <iostream>
#include <functional>

/**
 * Ce template permet de mettre dans un flot de sortie quelconque
 * (cout, debugstream, fichier) une variable quelconque, pour autant
 * que l'opérateur << doit définit pour ce type.
 *
 * Le template possède un pointeur sur un flot, initialisé lors de la
 * construction, et un méthode operator(), qui permet de remplir le
 * flot et de le retourner.
 *
 * @author Johan "Solo" Luisier
 */
template< typename T >
class EcrireElementConteneur : std::unary_function <T,std::ostream&>
{
 public:
  /**
   * Constructeur par défaut, initialise le flot qui sera utilisé.
   *
   * @param os flot de sortie, par défaut cout.
   * @param pref préfixe, est ajouté devant chaque valeur, par défaut
   * chaîne vide.
   * @param suf suffixe, est ajouté à la fin de chaque valeur, apr
   * défaut on ajout une espace.
   */
 EcrireElementConteneur( std::ostream* os = std::cout,
			 const std::string& pref = "",
			 const std::string& suf = " " )
   : flot( os ), prefixe( pref ), suffixe( suf )
  {};
  /**
   * Destructeur. On fait un flush, pour être sûr de tout afficher.
   */
  ~EcrireElementConteneur()
    {
      *flot << std::flush;
    };
  /**
   * Réalise l'affichage (ou le remplissage du fichier) avec la valeur
   * passée en argument.
   *
   * @param type variable qui sera écrite dans le flot.
   * @return le flot de sortie.
   */
  std::ostream& operator()(const T& type) const
    {
      return *flot << prefixe << type << suffixe;
    };
 private:
  /**
   * Pointeur sur le flot utilisé.
   */
  std::ostream* flot;
  /**
   * Est ajouté devant la valeur lors de la sortie sur le flot
   */
  std::string prefixe;
  /**
   * Est ajouté derrière la valeur lors de la sortie sur le flot
   */
  std::string suffixe;
};

/**
 * Ce template permet d'extraire une clé d'un conteneur du type
 * std::map, de manière générique. Le but est de l'utiliser dans une
 * boucle for_each.
 *
 * @author Johan "Solo" Luisier
 */
template< typename Clef, typename Valeur >
struct  ExtraireClef : std::unary_function < std::pair<Clef, Valeur>, Clef>
{
  /**
   * Renvoie la clé d'un élément d'une std::map.
   *
   * @param paire paire associant un élément de type Clef à un élément
   * de type Valeur. Un tel objet peut être un élément d'un conteneur
   * du type std::map.   
   *  @return paire.first, qui est du type Clef et est la clé de
   *  l'élément du conteneur associatif.
   */
  Clef operator()( const std::pair< Clef, Valeur >& paire )
  {
    return paire . first;
  };
};

/**
 * Ce template permet d'extraire une valeur d'un conteneur du type
 * std::map, de manière générique. Le but est de l'utiliser dans une
 * boucle for_each.
 *
 * @author Johan "Solo" Luisier
 */
template< typename Clef, typename Valeur >
struct  ExtraireValeur : std::unary_function < std::pair<Clef, Valeur>, Clef>
{
  /**
   * Renvoie la valeur d'un élément d'une std::map.
   *
   * @param paire paire associant un élément de type Clef à un élément
   * de type Valeur. Un tel objet peut être un élément d'un conteneur
   * du type std::map.
   *  @return paire.second, qui est du type Valeur et est la valeur de
   *  l'élément du conteneur associatif.
   * 
   */
  Clef operator()( const std::pair< Clef, Valeur >& paire )
  {
    return paire . second;
  };
};

#endif // ATL_H
